/********************
* aib X fifox <-> noc
*********************/

`define MRK 159:158
`define SUN 157 // subnet bit
`define VAL 156 // valid
`define DAT 155:155-127 // data bits
`define YM1 27  // yummy1 bit
`define YM0 26  // yummy0 bit
`define YM2 25  //长线
`define KEY 24  //判断是否走长线
`define LFT 23:0

module aib_mac_qua #(
    parameter DW=128,
    parameter MW=160
)(
    input nclk, // noc clk
    input mclk, // aib mac clk
    input rst,
    //当前die的坐标值[高三位为diex,低三位为diey]
    input [2:0] CX,  
    input [2:0] CY,
    // MAC/PHY data interface, QUARTER channel
    output [MW-1:0] data_in_f,
    input [MW-1:0] data_out_f,
    // MAC/router interface to 2 subnet routers
    input [DW-1:0] i_data0,
    input i_valid0,
    output o_yummy0,
    output [DW-1:0] o_data0,
    output o_valid0,
    input i_yummy0,
    input [DW-1:0] i_data1,
    input i_valid1,
    output o_yummy1,
    output [DW-1:0] o_data1,
    output o_valid1,
    input i_yummy1,
    input [DW-1:0] i_data2,  //长线fifo
    input i_valid2,
    output o_yummy2,
    output [DW-1:0] o_data2, //长线fifo
    output o_valid2,
    input i_yummy2
);
    localparam ASIZE = 3;
    localparam MEMSIZE = 4;
    //add
    wire[2:0] destX;
    wire[2:0] destY;
    wire[2:0] sourceX;
    wire[2:0] sourceY;
    wire key;

    // mac <- n0f(fifo) <- noc0;
    // mac <- n1f(fifo) <- noc1;
    //2个sr和1个长线  2代表长线
    wire [DW-1:0] n0f_rdata, n1f_rdata, n2f_rdata, nxf_rdata;  
    wire n0f_ren, n1f_ren,n2f_ren;
    wire n0f_empty, n1f_empty, n2f_empty;

    // data: aib -> mac X mxf(fifo) -> nocx;
    wire [DW-1:0] m0f_wdata, m1f_wdata, m2f_wdata;
    wire m0f_wval, m1f_wval, m2f_wval;
    wire m0f_ren, m1f_ren, m2f_ren;
    wire m0f_empty, m1f_empty, m2f_empty;

    // data_out_f field
    // prefix a_ denotes signals from AIB
    wire a_sel;
    wire a_valid;
    wire [DW-1:0] a_data;
    wire a_yummy1;
    wire a_yummy0;
    wire a_yummy2;  //长线
    wire a_key;
    wire n0ma_yummy; // n0 -> mac -> aib
    wire n1ma_yummy;
    wire n2ma_yummy;
    async_fifo #(
        .DSIZE(DW),
        .MEMSIZE(MEMSIZE),
        .ASIZE(ASIZE)
    ) u_af_n0m(
        .wclk(nclk),
        .wreset(rst),
        .wval(i_valid0),
        .wdata(i_data0),
        .wfull(),
        .rclk(mclk),
        .rreset(rst),
        .ren(n0f_ren),
        .rdata(n0f_rdata),
        .rempty(n0f_empty)
    );
    async_fifo #(
        .DSIZE(DW),
        .MEMSIZE(MEMSIZE),
        .ASIZE(ASIZE)
    ) u_af_n1m(
        .wclk(nclk),
        .wreset(rst),
        .wval(i_valid1),
        .wdata(i_data1),
        .wfull(),
        .rclk(mclk),
        .rreset(rst),
        .ren(n1f_ren),
        .rdata(n1f_rdata),
        .rempty(n1f_empty)
    );
    //modified (It is as same as the u_af_n1m before) 11.30
    async_fifo #(
        .DSIZE(DW),
        .MEMSIZE(MEMSIZE),
        .ASIZE(ASIZE)
    ) u_af_n2m(   //long wire->m的第一个 
        .wclk(nclk),
        .wreset(rst),
        .wval(i_valid2),
        .wdata(i_data2),
        .wfull(),
        .rclk(mclk),
        .rreset(rst),
        .ren(n2f_ren),
        .rdata(n2f_rdata),
        .rempty(n2f_empty)
    );
    arbiter  u_arbiter (
        .clk(mclk),
        .rst(rst),
        .mode(1),
        .empty0   (n0f_empty),
        .yummy0   (a_yummy0 ),
        .f_ren0   (n0f_ren  ),

        .empty1   (n1f_empty),
        .yummy1   (a_yummy1 ),
        .f_ren1   (n1f_ren  ),

        .empty2   (n2f_empty),
        .yummy2   (a_yummy2 ),
        .f_ren2   (n2f_ren  ),

        .sel      (sel      ),
        .validout (validout )
    );

    // aib <- mux X fifox <- nocx
    assign nxf_rdata= sel ? n1f_rdata : n0f_rdata;
    assign destX=data_in_f[155:153];
    assign key = !(CX+1==destX || CX-1==destX);
    // data_in_f field
    assign data_in_f[`MRK]= 0;
    assign data_in_f[`SUN]= sel;
    assign data_in_f[`VAL]= validout;
    assign data_in_f[`DAT]= nxf_rdata;
    assign data_in_f[`YM1]= n1ma_yummy;
    assign data_in_f[`YM0]= n0ma_yummy;
    assign data_in_f[`YM2]= n2ma_yummy;
    assign data_in_f[`KEY]= key;
    assign data_in_f[`LFT]= 0;

    synchronizer u_syn_mn0(
        .rclk(mclk),
        .rrst(rst),
        .ren(n0f_ren),
        .wclk(nclk),
        .wrst(rst),
        .yummy(o_yummy0)
    );
    synchronizer u_syn_mn1(
        .rclk(mclk),
        .rrst(rst),
        .ren(n1f_ren),
        .wclk(nclk),
        .wrst(rst),
        .yummy(o_yummy1)
    );
    synchronizer u_syn_mn2(
        .rclk(mclk),
        .rrst(rst),
        .ren(n2f_ren),
        .wclk(nclk),
        .wrst(rst),
        .yummy(o_yummy2)
    );


    /***********************************************
    * aib -> X fifox -> nocx
    ***********************************************/
    assign a_sel=data_out_f[`SUN];   //a_sel 标识 子网
    assign a_valid=data_out_f[`VAL];
    assign a_data=data_out_f[`DAT];
    assign a_yummy1=data_out_f[`YM1];
    assign a_yummy0=data_out_f[`YM0];
    assign a_yummy2=data_out_f[`YM2];
    assign a_key=data_out_f[`KEY];
    // demux

    // assign m0f_wdata= ~a_sel ? a_data : 0;
    // assign m1f_wdata= a_sel ? a_data : 0;
    // assign m0f_wval= ~a_sel && a_valid;
    // assign m1f_wval= a_sel && a_valid;

    
    assign m0f_wdata=(!a_key&&~a_sel) ? a_data : 0;
    assign m1f_wdata= (!a_key&& a_sel) ? a_data : 0;
    assign m2f_wdata= a_key ? a_data : 0;
    assign m0f_wval= ~a_sel && a_valid;
    assign m1f_wval= a_sel && a_valid;
    assign m2f_wval= a_valid;

    async_fifo #(
        .DSIZE(DW),
        .MEMSIZE(MEMSIZE),
        .ASIZE(ASIZE)
    ) u_af_mn0(
        .wclk(mclk),
        .wreset(rst),
        .wval(m0f_wval),
        .wdata(m0f_wdata),
        .wfull(),
        .rclk(nclk),
        .rreset(rst),
        .ren(m0f_ren),
        .rdata(o_data0),
        .rempty(m0f_empty)
    );
    async_fifo #(
        .DSIZE(DW),
        .MEMSIZE(MEMSIZE),
        .ASIZE(ASIZE)
    ) u_af_mn1(
        .wclk(mclk),
        .wreset(rst),
        .wval(m1f_wval),
        .wdata(m1f_wdata),
        .wfull(),
        .rclk(nclk),
        .rreset(rst),
        .ren(m1f_ren),
        .rdata(o_data1),
        .rempty(m1f_empty)
    );
    async_fifo #(
        .DSIZE(DW),
        .MEMSIZE(MEMSIZE),
        .ASIZE(ASIZE)
    ) u_af_mn2(   //m->noc1的第二个 
        .wclk(mclk),
        .wreset(rst),
        .wval(m2f_wval),
        .wdata(m2f_wdata),
        .wfull(),
        .rclk(nclk),
        .rreset(rst),
        .ren(m2f_ren),
        .rdata(o_data2),
        .rempty(m2f_empty)
    );

    flow_con u_m0fc(
        .clk(nclk),
        .rst(rst),
        .f_e(m0f_empty),
        .f_r(m0f_ren),
        .r_y(i_yummy0)
    );
    flow_con u_m1fc(
        .clk(nclk),
        .rst(rst),
        .f_e(m1f_empty),
        .f_r(m1f_ren),
        .r_y(i_yummy1)
    );
        flow_con #(
        .CREDIT(MEMSIZE),
        .W(3)   // 2^W > CREDIT
    )u_m2fc(
        .clk(nclk),
        .rst(rst),
        .f_e(m2f_empty),
        .f_r(m2f_ren),
        .r_y(i_yummy2)
    );


    assign o_valid0=m0f_ren;
    assign o_valid1=m1f_ren;
    assign o_valid2=m2f_ren;
    synchronizer u_syn_n0m(
        .rclk(nclk),
        .rrst(rst),
        .ren(m0f_ren),
        .wclk(mclk),
        .wrst(rst),
        .yummy(n0ma_yummy)
    );
    synchronizer u_syn_n1m(
        .rclk(nclk),
        .rrst(rst),
        .ren(m1f_ren),
        .wclk(mclk),
        .wrst(rst),
        .yummy(n1ma_yummy)
    );
    synchronizer u_syn_n2m(
        .rclk(nclk),
        .rrst(rst),
        .ren(m2f_ren),
        .wclk(mclk),
        .wrst(rst),
        .yummy(n2ma_yummy)
    );
    
endmodule

